home *** CD-ROM | disk | FTP | other *** search
/ The Business Master (3rd Edition) / The Business Master (3rd Edition).iso / files / utilstic / showmcb / ramview.asm next >
Encoding:
Assembly Source File  |  1992-06-17  |  48.1 KB  |  1,121 lines

  1. ;----------------------------------------------------------------
  2. ; RAMVIEW: A memory-resident memory-viewer.
  3. ; Frank Dever & David Thomas, WindowDOS Associates
  4. ;----------------------------------------------------------------
  5. CR              EQU     13              ;carriage return
  6. LF              EQU     10              ;line feed
  7. U_ARR           EQU     72              ;up arrow
  8. D_ARR           EQU     80              ;down arrow
  9. PGUP            EQU     73              ;page up
  10. PGDN            EQU     81              ;page down
  11. L_ARR           EQU     75              ;left arrow
  12. R_ARR           EQU     77              ;right arrow
  13. HOME            EQU     71              ;home
  14. END_KEY         EQU     79              ;end
  15. ;----------------------------------------------------------------------
  16. HOTKEY          EQU     58h             ;F12
  17. SHIFT_MASK      EQU     0               ;Unshifted
  18. INT9_BUSY       EQU     1
  19. INT10_BUSY      EQU     2
  20. INT16_BUSY      EQU     4
  21. VIDEO_BUF       EQU TopStack - 4260     ;Buffer & Stack after code
  22. ;----------------------------------------------------------------------
  23. _TEXT   SEGMENT PARA    PUBLIC  'CODE'
  24.         ASSUME  CS:_TEXT,DS:_TEXT
  25.                 ORG     100h
  26. BEGIN:          JMP     START
  27. ;Resident Data
  28. INSTALLED       DB  "RAMVIEW 2.00 (c) 1992 PC Magazine",9,9,254
  29.                 DB  " The Hotkey is F12 ",254,CR,LF,"$",8,32,8,26
  30. UNINSTALLED     DB  "RAMVIEW Uninstalled",CR,LF,"$"
  31.  
  32. DISABLE         DB  0                   ;flag for de-installation
  33.  
  34. LABEL0          DB " ABS  SEG  OFF   0  1  2  3  4  5  6  7"
  35.                 DB "  8  9  A  B  C  D  E  F       ASCII",0
  36.  
  37. START_DISPLAY   DB " GOTO ADDRESS: 0000:0000",0
  38.  
  39. COMMANDLINE     DB "(G)oto   (H)ex Search   (A)scii Search   (N)ext"
  40.                 DB  "     ",24," ",25," PgUp PgDn Home End Esc ",0
  41.  
  42. CURSOR_POS          DW 0
  43. CURSOR_TYPE         DW 0607H            ;for turning cursor on/off
  44. START_OFFSET        DW 0                ;top addr shown on screen
  45. START_SEGMENT       DW 0
  46. END_OFFSET          DW 0FH              ;last segment in search
  47. END_SEGMENT         DW 0FFFFH           ;fixed to ffff:f
  48. SEARCH_SEGMENTS     DW 0                ;# segments to search
  49. SEARCH_BYTES        DW 0                ;# bytes left after search
  50. HEX_SIEVE           DB " "                      ;hex with space
  51. ADDR_SIEVE          DB "01234567890ABCDEF"      ;hex without space
  52. CHAR_SIEVE          DB 0                        ;all characters
  53. ASCII_SEARCH_PROMPT DB "ASCII Search String: ",0;ascii search prompt
  54. HEX_SEARCH_PROMPT   DB "HEX Search String: ",0  ;hex search prompt
  55. ASCII_SEARCH_AREA   DB 20 DUP (" "),0           ;ascii search string
  56. HEX_SEARCH_AREA     DB 20 DUP (" "),0           ;hex search string
  57. LAST_SEARCH_STRING  DW 0                ;pointer to last string
  58. LAST_STRING_LENGTH  DW 0                ;last string length
  59. OUR_SS              DW 0
  60. OUR_SP              DW 0
  61. THEIR_SS            DW 0
  62. THEIR_SP            DW 0
  63. ADDR_INT9H          DD 0
  64. ADDR_INT10H         DD 0
  65. BIOS_SEG            DW 40H
  66. DIFF                DW 0                ;# of chars on a line > 80
  67. ROW                 DW 0                ;display row counter
  68. BUSY                DB 0
  69. ;Resident Code
  70. ;----------------------------------------------------------------------
  71. START   PROC    NEAR
  72.         CLD
  73.         CALL    PROGRAM_ALREADY_IN
  74.         JNZ     NOT_IN                  ;Install or
  75.         CALL    UNINSTALL               ;Un-Install
  76.         MOV     AX,4C01h
  77.         INT     21h
  78. NOT_IN: MOV     OUR_SS,CS               ;Set Stack Segment
  79.         MOV     OUR_SP,OFFSET TopStack  ;and Pointer
  80.         CALL    INSTALL
  81.         MOV     DX,OFFSET INSTALLED
  82.         MOV     AH,9                    ;Say Installed
  83.         INT     21h
  84.         MOV     DX,OFFSET TopStack+15   ;Convert Length
  85.         MOV     CL,4                    ;into Paragraphs
  86.         SHR     DX,CL
  87.         MOV     AX,3100h                ;TSR Code, Video
  88.         INT     21h                     ;Buffer and Stack
  89. START   ENDP
  90. ;----------------------------------------------------------------------
  91. INT10H  PROC    FAR
  92.         OR      CS:BUSY,INT10_BUSY      ;recursion protection
  93.         PUSHF
  94.         CALL    CS:ADDR_INT10H
  95.         PUSHF
  96.         AND     CS:BUSY,NOT(INT10_BUSY)
  97.         POPF
  98.         RET     2                       ;preserve flags
  99. INT10H  ENDP
  100. ;----------------------------------------------------------------------
  101. INT9H   PROC    FAR
  102.         STI
  103.         PUSH    AX                      ;Preserve working register
  104.         CMP     CS:DISABLE,-1           ;If DISABLED
  105.         JE      NOT_US                  ;Then Do NOTHING
  106.         IN      AL,60h                  ;Else Get Key Port KEY
  107.         CMP     AL,HOTKEY               ;If NOT HotKey
  108.         JNE     NOT_US                  ;Then Do NOTHING
  109.         MOV     AH,2                    ;Else Get Shift Status
  110.         INT     16h
  111.         AND     AL,0Fh
  112.         CMP     AL,SHIFT_MASK           ;If NOT Shift Combination
  113.         JNE     NOT_US                  ;Then Do NOTHING
  114.         IN      AL,61h                  ;Else RESET
  115.         MOV     AH,AL                   ;KEYBOARD
  116.         OR      AL,80h
  117.         OUT     61h,AL
  118.         MOV     AL,AH                   ;After a
  119.         JMP     SHORT $+2               ;DELAY
  120.         OUT     61h,AL
  121.         CLI
  122.         MOV     AL,20h                  ;RESET
  123.         OUT     20h,AL                  ;INT Controller
  124.         STI
  125.         CMP     CS:BUSY,0               ;AVOID
  126.         JNE     WE_ARE_BUSY             ;RE-ENTRANCE
  127.         OR      CS:BUSY,INT9_BUSY
  128.         CALL    ADJUST_FOR_VIDEO_MODE   ;If NOT Text or => 80 cols
  129.         JC      CANT_POP_UP             ;Then Can't Display Properly
  130.         CALL    TSRMAIN                 ;Else Display 80x25 RamView
  131. CANT_POP_UP:
  132.         CLI                             ;Hold Interrupts while
  133.         AND     CS:BUSY,NOT(INT9_BUSY)  ;Reset RamView NOT Busy
  134. WE_ARE_BUSY:
  135.         POP     AX
  136.         IRET
  137. NOT_US:
  138.         POP     AX
  139.         JMP     CS:ADDR_INT9H
  140. INT9H   ENDP
  141. ;----------------------------------------------------------------------
  142. ADJUST_FOR_VIDEO_MODE   PROC    NEAR
  143.         PUSH    BX
  144.         MOV     AH,15                   ;Get present mode
  145.         INT     10h
  146.         CMP     AH,80                   ;If Below 80 Columns
  147.         JB      BAD_MODE                ;Then Wrong Mode
  148.         MOV     BYTE PTR CS:DIFF,AH     ;Else CALCULATE
  149.         SUB     CS:BYTE PTR DIFF,80     ;EXTRA ROOM
  150.         CMP     AL,7                    ;If NOT Mono
  151.         JNE     TRY_COLOR               ;Then COLOR?
  152. MODE_OK:
  153.         CLC
  154.         POP     BX
  155.         RET
  156. TRY_COLOR:
  157.         CMP     AL,3                    ;If 1 - 3
  158.         JBE     MODE_OK                 ;Then 80x25
  159. BAD_MODE:                               ;Else NOT Ok
  160.         STC
  161.         POP     BX
  162.         RET
  163. ADJUST_FOR_VIDEO_MODE   ENDP
  164. ;-----------------------------------------------------------------
  165. ;main routine called by pressing hot key
  166. ;-----------------------------------------------------------------
  167. TSRMAIN PROC    NEAR
  168.         CALL    SWAPIN                  ;new stack
  169.         MOV     AX,CS                   ;our data segment
  170.         MOV     DS,AX
  171.         CALL    SAVE_CURSOR             ;save cursor
  172.         CALL    CURSOR_OFF              ;turn cursor off
  173.         CALL    SAVE_SCREEN             ;save screen
  174.         CALL    CLEAR_SCREEN            ;clear screen
  175.         XOR     AX,AX                   ;row 0
  176.         MOV     BX,AX                   ;col 0
  177.         MOV     SI,OFFSET LABEL0        ;bottom line
  178.         CALL    DISPLAY_STRING          ;show header line
  179. NEXT_SCREEN:
  180.         CALL    BODY                    ;put hex display up
  181.         MOV     AX,24                   ;last row
  182.         XOR     BX,BX                   ;column 0
  183.         MOV     SI,OFFSET COMMANDLINE
  184.         CALL    DISPLAY_STRING          ;show it
  185.         CALL    MENU                    ;go get keystroke
  186.         JNC     NEXT_SCREEN             ;until esc is pressed
  187.  
  188.         CALL    RESTORE_SCREEN          ;put screen back
  189.         CALL    CURSOR_ON               ;turn cursor on
  190.         CALL    RESTORE_CURSOR
  191.         CALL    SWAPOUT                 ;restore stack
  192.         RET
  193. TSRMAIN ENDP
  194. ;-----------------------------------------------------------------
  195. ;cursor routines
  196. ;-----------------------------------------------------------------
  197. SAVE_CURSOR PROC NEAR
  198.         MOV     ES,BIOS_SEG
  199.         MOV     AX,ES:[60H]             ;get present cursor type
  200.         MOV     CURSOR_TYPE,AX          ;save it
  201.         CALL    GETPOS
  202.         MOV     CURSOR_POS,DX
  203.         RET
  204. SAVE_CURSOR ENDP
  205. ;----------------------------------------------------------------------
  206. RESTORE_CURSOR PROC NEAR
  207.         MOV     DX,CURSOR_POS
  208.         CALL    SETPOS
  209.         RET
  210. RESTORE_CURSOR ENDP
  211. ;----------------------------------------------------------------------
  212. SETPOS  PROC    NEAR
  213.         MOV     AH,2                    ;set cursor position
  214.         XOR     BH,BH                   ;active page
  215.         INT     10H                     ;set cursor position to dx
  216.         RET
  217. SETPOS  ENDP
  218. ;----------------------------------------------------------------------
  219. GETPOS  PROC    NEAR
  220.         MOV     AH,3                    ;get cursor position
  221.         XOR     BH,BH                   ;active page
  222.         INT     10H                     ;get cursor position in dx
  223.         RET
  224. GETPOS  ENDP
  225. ;----------------------------------------------------------------------
  226. CURSOR_OFF PROC NEAR
  227.         PUSH    CX
  228.         MOV     CX,2B0CH                ;turn off cursor value
  229.         CALL    SETCUR
  230.         POP     CX
  231.         RET
  232. CURSOR_OFF ENDP
  233. ;----------------------------------------------------------------------
  234. CURSOR_ON  PROC NEAR
  235.         PUSH    CX
  236.         MOV     CX,CURSOR_TYPE          ;turn on cursor value
  237.         CALL    SETCUR
  238.         POP     CX
  239.         RET
  240. CURSOR_ON  ENDP
  241. ;----------------------------------------------------------------------
  242. SETCUR  PROC    NEAR
  243.         PUSH    AX
  244.         MOV     AH,1                    ;function to set cursor shape
  245.         INT     10H
  246.         POP     AX
  247.         RET
  248. SETCUR  ENDP
  249. ;-----------------------------------------------------------------
  250. ;screen routines
  251. ;-----------------------------------------------------------------
  252. SAVE_SCREEN     PROC    NEAR
  253.         PUSH    DS                      ;save data segment
  254.         XOR     AX,AX
  255.         MOV     BX,AX
  256.         CALL    CALC_SCRN_ADDR          ;address of (0,0)
  257.         MOV     SI,OFFSET VIDEO_BUF
  258.         PUSH    DS
  259.         PUSH    ES
  260.         POP     DS
  261.         POP     ES
  262.         XCHG    DI,SI
  263.         MOV     BX,25
  264. SAVE_NEXT_LINE:
  265.         MOV     CX,80                   ;save an 80
  266.         REP     MOVSW                   ;word line
  267.         ADD     SI,CS:DIFF              ;get video
  268.         ADD     SI,CS:DIFF              ;next line
  269.         DEC     BX                      ;25 lines =
  270.         JNZ     SAVE_NEXT_LINE          ;2000 words
  271.         POP     DS
  272.         RET
  273. SAVE_SCREEN     ENDP
  274. ;-----------------------------------------------------------------
  275. CLEAR_SCREEN    PROC    NEAR
  276.         XOR     AX,AX
  277.         MOV     BX,AX
  278.         CALL    CALC_SCRN_ADDR          ;address of (0,0)
  279.         MOV     AX,0720H                ;space with normal attribute
  280.         MOV     BX,24
  281. CLEAR_NEXT_LINE:
  282.         MOV     CX,80
  283.         REP     STOSW                   ;words
  284.         ADD     DI,CS:DIFF              ;go to next
  285.         ADD     DI,CS:DIFF              ;line
  286.         DEC     BX                      ;24 lines
  287.         JNZ     CLEAR_NEXT_LINE
  288.         RET
  289. CLEAR_SCREEN    ENDP
  290. ;-----------------------------------------------------------------
  291. RESTORE_SCREEN  PROC    NEAR
  292.         XOR     AX,AX
  293.         MOV     BX,AX
  294.         CALL    CALC_SCRN_ADDR          ;address of (0,0)
  295.         MOV     SI,OFFSET VIDEO_BUF
  296.         MOV     BX,25
  297. RESTORE_NEXT_LINE:
  298.         MOV     CX,80                   ;save 2000
  299.         REP     MOVSW                   ;words
  300.         ADD     DI,CS:DIFF              ;go to next
  301.         ADD     DI,CS:DIFF              ;line
  302.         REP     MOVSW                   ;words
  303.         DEC     BX                      ;25 lines
  304.         JNZ     RESTORE_NEXT_LINE
  305.         RET
  306. RESTORE_SCREEN  ENDP
  307. ;-----------------------------------------------------------------
  308. ;Stack Routines
  309. ;-----------------------------------------------------------------
  310. RETADDR DW      0
  311. SWAPIN  PROC    NEAR
  312.         POP     CS:RETADDR              ;Save Caller's Address
  313.         MOV     CS:THEIR_SS,SS          ;Save Their Stack
  314.         MOV     CS:THEIR_SP,SP
  315.         MOV     SS,CS:OUR_SS            ;Switch to Our Stack
  316.         MOV     SP,CS:OUR_SP
  317.         PUSH    AX                      ;Preserve all registers
  318.         PUSH    BX
  319.         PUSH    CX
  320.         PUSH    DX
  321.         PUSH    SI
  322.         PUSH    DI
  323.         PUSH    ES
  324.         PUSH    DS
  325.         PUSH    BP
  326.         JMP     CS:RETADDR              ;Return to Caller
  327. SWAPIN  ENDP
  328. ;-----------------------------------------------------------------
  329. SWAPOUT PROC    NEAR
  330.         POP     CS:RETADDR              ;Save Caller's Address
  331.         POP     BP                      ;Restore All Registers
  332.         POP     DS
  333.         POP     ES
  334.         POP     DI
  335.         POP     SI
  336.         POP     DX
  337.         POP     CX
  338.         POP     BX
  339.         POP     AX
  340.         MOV     SS,CS:THEIR_SS          ;Restore Caller's Stack
  341.         MOV     SP,CS:THEIR_SP
  342.         JMP     CS:RETADDR              ;Return to Caller
  343. SWAPOUT ENDP
  344. ;-----------------------------------------------------------------
  345. ;clears last line
  346. ;-----------------------------------------------------------------
  347. CLEAR_LAST_LINE PROC NEAR
  348.         MOV     AX,24                   ;row 24
  349.         XOR     BX,BX                   ;col 0
  350.         CALL    CALC_SCRN_ADDR          ;get es:di for that address
  351.         MOV     CX,80                   ;80 words
  352.         MOV     AX,0720H                ;normal attribute spaces
  353.         REP     STOSW                   ;clear it
  354.         RET
  355. CLEAR_LAST_LINE ENDP
  356. ;-----------------------------------------------------------------
  357. ;menu accept and key input
  358. ;-----------------------------------------------------------------
  359. MENU PROC NEAR
  360. NEXT_MENU_KEY:
  361.         CALL    GETKEY                  ;input a key
  362.         CMP     AH,2                    ;if scan code below 2
  363.         JBE     QUIT_EXIT               ;then key is ESCape
  364. NOT_ESC:
  365.         AND     AL,0DFH                 ;make all ascii caps
  366.         CMP     AL,"G"                  ;G)o
  367.         JNZ     NOT_GOTO
  368.         CALL    GO_TO                   ;get start addr
  369.         JMP     SHORT MENU_EXIT
  370. NOT_GOTO:
  371.         CMP     AL,"A"                  ;A)scii search
  372.         JNZ     NOT_ASCII_SEARCH
  373.         CALL    ASCII_SEARCH            ;find ascii string
  374.         JMP     SHORT MENU_EXIT
  375. NOT_ASCII_SEARCH:
  376.         CMP     AL,"H"                  ;H)ex search
  377.         JNZ     NOT_HEX_SEARCH
  378.         CALL    HEX_SEARCH              ;find hex string
  379.         JMP     SHORT MENU_EXIT
  380. NOT_HEX_SEARCH:
  381.         CMP     AL,"N"                  ;N)ext search
  382.         JNZ     NOT_NEXT_SEARCH
  383.         CALL    NEXT_SEARCH             ;find next string
  384.         JMP     SHORT MENU_EXIT
  385. NOT_NEXT_SEARCH:
  386.         CMP     AH,U_ARR                ;up arrow
  387.         JNZ     NOT_UP
  388.         MOV     AX,-10H
  389.         JMP     SHORT MOVEIT
  390. NOT_UP:
  391.         CMP     AH,HOME                 ;go to beginning of memory
  392.         JNZ     NOT_HOME
  393.         MOV     START_OFFSET,0
  394.         MOV     START_SEGMENT,0
  395.         JMP     SHORT MENU_EXIT
  396. NOT_HOME:
  397.         CMP     AH,END_KEY              ;go to end of memory
  398.         JNZ     NOT_END
  399.         MOV     START_OFFSET,0FE90H     ;top of last page
  400.         MOV     START_SEGMENT,0F000H
  401.         JMP     SHORT MENU_EXIT
  402. NOT_END:
  403.         CMP     AH,D_ARR                ;down arrow
  404.         JNZ     NOT_DOWN
  405.         MOV     AX,10H
  406.         JMP     SHORT MOVEIT
  407. NOT_DOWN:
  408.         CMP     AH,PGUP                 ;page up
  409.         JNZ     NEXT_CHECK
  410.         MOV     AX,-170H
  411.         JMP     SHORT MOVEIT
  412. NEXT_CHECK:
  413.         CMP     AH,PGDN                 ;page down
  414.         MOV     AX,170H
  415.         JZ      MOVEIT
  416.         JMP     NEXT_MENU_KEY
  417. MOVEIT: CALL    MOVE
  418. MENU_EXIT:
  419.         CLC                             ;clear carry for exit
  420. QUIT_EXIT:
  421.         RET
  422. MENU ENDP
  423. ;-----------------------------------------------------------------
  424. ;sets starting segment and offset for display
  425. ;-----------------------------------------------------------------
  426. MOVE    PROC    NEAR
  427.         OR      AX,AX                   ;is the movement signed
  428.         JNS     ADDIT                   ;no-add to seg:off
  429.         NEG     AX                      ;otherwise make positive
  430.         SUB     START_OFFSET,AX         ;subtract from offset
  431.         JNC     MOVE_EXIT               ;if no carry, done
  432.         SUB     START_SEGMENT,1000H     ;else wrap segment
  433.         JMP     SHORT MOVE_EXIT
  434. ADDIT:  ADD     START_OFFSET,AX         ;add movement to offset
  435.         JNC     MOVE_EXIT               ;if no carry, done
  436.         ADD     START_SEGMENT,1000H     ;else wrap segment
  437. MOVE_EXIT:
  438.         RET
  439. MOVE ENDP
  440. ;-----------------------------------------------------------------
  441. ;ascii search routine
  442. ;-----------------------------------------------------------------
  443. ASCII_SEARCH    PROC    NEAR
  444.         CALL    CLEAR_LAST_LINE         ;clear line for input
  445.         MOV     AX,24                   ;last row
  446.         XOR     BX,BX                   ;first col
  447.         MOV     SI,OFFSET ASCII_SEARCH_PROMPT
  448.         CALL    DISPLAY_STRING          ;show the prompt
  449.         CALL    STRLEN                  ;find out how long prompt is
  450.         MOV     DL,CL                   ;dl = col after prompt
  451.         MOV     DH,24                   ;dx = row col
  452.         MOV     SI,OFFSET ASCII_SEARCH_AREA     ;
  453.         MOV     CX,20                   ;size of the string
  454.         CALL    CLEAR_BUF
  455.         MOV     DI,OFFSET CHAR_SIEVE    ;pointer to sieve
  456.         MOV     BX," "                  ;get
  457.                 ;dx=row col,cx=size,bl=replace,si=prompt,di=sieve
  458.         CALL    INPUT
  459.         MOV     SI,OFFSET ASCII_SEARCH_AREA
  460.         MOV     LAST_SEARCH_STRING,SI   ;save ptr to str for next
  461.         CALL    STRLEN                  ;how long?
  462.         MOV     LAST_STRING_LENGTH,CX   ;save length for next
  463.         JCXZ    NO_SEARCH               ;if not, dont search
  464.         CALL    SEARCH_MEM              ;cx=length si=string
  465. NO_SEARCH:
  466.         RET
  467. ASCII_SEARCH    ENDP
  468. ;-----------------------------------------------------------------
  469. ;find next occurrence
  470. ;-----------------------------------------------------------------
  471. NEXT_SEARCH     PROC    NEAR
  472.         MOV     SI,LAST_SEARCH_STRING   ;get address of last string
  473.         MOV     CX,LAST_STRING_LENGTH
  474.         JCXZ    NO_NEXT                 ;dont search
  475.         ADD     START_OFFSET,1          ;move over one to start
  476.         JNC     NOS_WRAP                ;if it causes wrap,
  477.         ADD     START_SEGMENT,1000H     ;wrap segment
  478. NOS_WRAP:
  479.         CALL    SEARCH_MEM              ;search for next string
  480. NO_NEXT:
  481.         RET
  482. NEXT_SEARCH     ENDP
  483. ;-----------------------------------------------------------------
  484. ;hex search routine
  485. ;-----------------------------------------------------------------
  486. HEX_SEARCH  PROC    NEAR
  487.         CALL    CLEAR_LAST_LINE         ;clear line for input
  488.         MOV     SI,OFFSET HEX_SEARCH_PROMPT
  489.         MOV     AX,24                   ;last row
  490.         XOR     BX,BX                   ;first col
  491.         CALL    DISPLAY_STRING          ;show the prompt
  492.         CALL    STRLEN                  ;find out how long prompt is
  493.         MOV     DL,CL                   ;dl = col after prompt
  494.         MOV     DH,24                   ;dx = row col
  495.         MOV     SI,OFFSET HEX_SEARCH_AREA       ;
  496.         MOV     CX,20                   ;size of the string
  497.         CALL    CLEAR_BUF
  498.         MOV     DI,OFFSET HEX_SIEVE     ;pointer to sieve
  499.         MOV     BX," "                  ;replacement char
  500.                 ;dx=row col,cx=size,bx=replace,si=prompt,di=sieve
  501.         CALL    INPUT
  502.         MOV     SI,OFFSET HEX_SEARCH_AREA
  503.         CALL    STRLEN                  ;length of search string
  504.         CMP     CL,1                    ;must be at least two digits
  505.         JBE     NO_SEARCH               ;otherwise search fails
  506.         MOV     LAST_SEARCH_STRING,SI   ;save it
  507.         MOV     LAST_STRING_LENGTH,CX   ;save length
  508.         CALL    ELIMINATE_BLANKS        ;eliminate blanks in input
  509.         CALL    CONVERT_ASCII_HEX_TO_HEX_STRING ;string into hex
  510.         MOV     LAST_STRING_LENGTH,CX   ;save length
  511.         CALL    SEARCH_MEM              ;find it
  512. NOSEARCH:
  513.         RET
  514. HEX_SEARCH  ENDP
  515. ;-----------------------------------------------------------------
  516. ;clear ds:[si] with (cx) spaces
  517. ;-----------------------------------------------------------------
  518. CLEAR_BUF   PROC    NEAR
  519.             PUSH    CX
  520.             PUSH    SI
  521. CLEARIT:    MOV     BYTE PTR [SI]," "
  522.             INC     SI
  523.             LOOP    CLEARIT
  524.             POP     SI
  525.             POP     CX
  526.             RET
  527. CLEAR_BUF   ENDP
  528. ;-----------------------------------------------------------------
  529. ;translate ascii hex string to binary string, return size in cx
  530. ;-----------------------------------------------------------------
  531. CONVERT_ASCII_HEX_TO_HEX_STRING PROC NEAR
  532.             PUSH    SI              ;save si for use in main
  533.             MOV     DI,SI           ;duplicate si
  534.             MOV     BX,SI           ;for later use
  535. NEXTC:      LODSW                   ;get two ascii digits
  536.             OR      AL,AL           ;are we at the end
  537.             JZ      C_EXIT          ;if so, string is converted
  538.             OR      AH,AH           ;in case wrong # digits
  539.             JZ      C_EXIT          ;string is converted
  540.             CALL    ASCII_HEX_TO_HEX;translate ascii to binary
  541.             STOSB                   ;put back in string
  542.             JMP     NEXTC           ;get next two characters
  543. C_EXIT:     XOR     AL,AL           ;clear al
  544.             STOSB                   ;put terminator after this
  545.             SUB     DI,BX           ;find out how many bytes
  546.             LEA     CX,[DI-1]       ;we have converted
  547.             POP     SI              ;restore important register
  548.             RET
  549. CONVERT_ASCII_HEX_TO_HEX_STRING ENDP
  550. ;-----------------------------------------------------------------
  551. ;close up blanks in a string
  552. ;-----------------------------------------------------------------
  553. ELIMINATE_BLANKS PROC NEAR
  554.             PUSH    SI              ;save si for main
  555.             PUSH    DS              ;set ds:si and es:di to same
  556.             POP     ES
  557.             MOV     DI,SI
  558. NEXT_SQ:    LODSB                   ;get character
  559.             CMP     AL," "          ;if space
  560.             JZ      NEXT_SQ         ;skip it
  561.             STOSB                   ;otherwise store it
  562.             OR      AL,AL           ;if zero
  563.             JNZ     NEXT_SQ         ;done whole string
  564. SQUOZE:     POP     SI              ;restore important register
  565.             RET
  566. ELIMINATE_BLANKS ENDP
  567. ;-----------------------------------------------------------------
  568. ;go to command
  569. ;-----------------------------------------------------------------
  570. GO_TO   PROC    NEAR
  571.         CALL    CLEAR_LAST_LINE         ;clear line for input
  572.         MOV     AX,24                   ;row
  573.         XOR     BX,BX                   ;col
  574.         MOV     SI,OFFSET START_DISPLAY ;prompt
  575.         CALL    DISPLAY_STRING          ;show it
  576.         MOV     DX,180FH                ;row col
  577.         MOV     SI,OFFSET START_DISPLAY+15      ;destination
  578.         MOV     CX,9                    ;size
  579.         MOV     DI,OFFSET ADDR_SIEVE    ;sieve
  580.         MOV     BX,"0"                  ;replace char
  581.                 ;dx=row col,cx=size,bx=replace,si=prompt,di=sieve
  582.         CALL    INPUT
  583.         MOV     SI,OFFSET START_DISPLAY+15      ;ascii address
  584.         MOV     DI,OFFSET START_SEGMENT ;destination
  585.         CALL    CONVERT_ADDR            ;32 bit ascii address to ptr
  586.         CLC
  587.         RET
  588. GO_TO   ENDP
  589. ;-----------------------------------------------------------------
  590. ;convert ascii to binary segment and offset
  591. ; si=ascii  di= pointer to destination
  592. ;-----------------------------------------------------------------
  593. CONVERT_ADDR    PROC    NEAR
  594.         PUSH    DS
  595.         POP     ES                      ;set es for stos
  596.         INC     DI
  597.         CALL    CONVERT_BYTE            ;segment
  598.         CALL    CONVERT_BYTE
  599.         INC     SI                      ;colon
  600.         CALL    CONVERT_BYTE            ;offset
  601.         CALL    CONVERT_BYTE
  602.         RET
  603. CONVERT_ADDR    ENDP
  604. ;-----------------------------------------------------------------
  605. CONVERT_BYTE    PROC    NEAR
  606.         LODSW                           ;get two chars
  607.         CALL    ASCII_HEX_TO_HEX        ;make hex
  608.         MOV     [DI],AL                 ;put in destination
  609.         DEC     DI                      ;set up for next character
  610.         RET
  611. CONVERT_BYTE    ENDP
  612. ;-----------------------------------------------------------------
  613. ;display main screen
  614. ;-----------------------------------------------------------------
  615. BODY    PROC    NEAR
  616.         PUSH    BP              ;use the
  617.         MOV     BP,SP           ;stack
  618.         SUB     SP,8            ;for temporary variables
  619.         PUSH    DS              ;save ds for main routine
  620.         LES     BX,DWORD PTR START_OFFSET
  621.         MOV     [BP-2],BX       ;save on stack
  622.         MOV     [BP-4],ES       ;for later use
  623.         CALL    NORMALIZE       ;change es:bx so 10h <= bx >=0
  624.         MOV     [BP-6],BX       ;save value on stack
  625.         MOV     [BP-8],ES       ;for later use
  626.         MOV     DS,[BP-4]       ;get pointer
  627.         MOV     SI,[BP-2]       ;to memory to display
  628.         MOV     CS:ROW,0        ;initialize row counter
  629. NEXT_LINE:
  630.         INC     CS:ROW          ;next display row
  631.         MOV     AX,CS:ROW       ;row
  632.         XOR     BX,BX           ;col
  633.         CALL    CALC_SCRN_ADDR  ;get es:di for that address
  634.         MOV     CX,[BP-8]       ;hi part of norm 20 bit desc
  635.         CALL    WORD_OUT        ;print it
  636.         INC     WORD PTR[BP-8]  ;add 1 to seg = 16 bytes
  637.         MOV     AL,[BP-6]       ;get lo part
  638.         CALL    HEX_TO_ASCII_HEX;convert to ascii
  639.         XCHG    AL,AH           ;lowest significant nybble
  640.         CALL    CHAR_OUT        ;print lo part of 'ABS' value
  641.         CALL    SPACE_OUT       ;put separator
  642.         MOV     CX,[BP-4]       ;segment being displayed
  643.         CALL    WORD_OUT        ;print it
  644.         MOV     AL,":"          ;followed
  645.         CALL    CHAR_OUT        ;by a colon
  646.         MOV     CX,[BP-2]       ;offset this line
  647.         CALL    WORD_SPACE      ;print offset/space
  648.         MOV     CX,16           ;# characters to print
  649.         MOV     DX,SI           ;save ptr to present line
  650. HEX_PART:
  651.         LODSB                   ;get character
  652.         CALL    BYTE_OUT        ;print two hex nybbles
  653.         CALL    SPACE_OUT       ;print space
  654.         LOOP    HEX_PART        ;all 16 hex digits
  655.         MOV     SI,DX           ;get ptr to present line
  656.         MOV     CX,16           ;all 16 hex digits
  657.         MOV     AL,70H          ;reverse the ascii part
  658. ASCII_PART:
  659.         MOVSB                   ;print the ascii part
  660.         STOSB                   ;reverse attribute on it
  661.         LOOP    ASCII_PART      ;all 16 ascii chars
  662.         ADD     WORD PTR[BP-6],10H      ;'ABS' + 16
  663.         ADC     WORD PTR[BP-8],0        ;
  664.         ADD     WORD PTR[BP-2],10H      ;'SEG:OFF' + 16
  665.         JNC     NO_WRAP                 ;if it wraps
  666.         ADD     WORD PTR[BP-4],1000H    ;wrap the segment
  667.         MOV     DS,[BP-4]       ;get the data segment
  668. NO_WRAP:
  669.         CMP     CS:ROW,23       ;if not completely done
  670.         JB      NEXT_LINE       ;do another
  671.         POP     DS              ;restore ds for main routine
  672.         ADD     SP,8            ;clean off temporary variables
  673.         POP     BP              ;restore bp
  674.         RET
  675. BODY    ENDP
  676. ;-----------------------------------------------------------------
  677. WORD_SPACE LABEL NEAR
  678.         CALL    WORD_OUT        ;output two nybbles from cx
  679. SPACE_OUT LABEL NEAR
  680.         MOV     AL," "          ;output a space
  681.         JMP     SHORT CHAR_OUT
  682. WORD_OUT LABEL NEAR
  683.         MOV     AL,CH           ;get high nybble
  684.         CALL    BYTE_OUT        ;print it
  685.         MOV     AL,CL           ;get low nybble
  686. BYTE_OUT LABEL NEAR
  687.         CALL    HEX_TO_ASCII_HEX;cvt hex to two char nybbles
  688.         STOSB                   ;print highest order nybble
  689.         INC     DI              ;skip attribute
  690.         MOV     AL,AH           ;get low order nybble
  691. CHAR_OUT LABEL NEAR
  692.         STOSB                   ;print it
  693.         INC     DI              ;skip attribute
  694.         RET
  695. ;-----------------------------------------------------------------
  696. END_MINUS_START PROC    NEAR
  697.         LES     BX,DWORD PTR START_OFFSET   ;get start seg:off
  698.         CALL    NORMALIZE       ;change es:bx so 10h <= bx >=0
  699.         MOV     AX,ES           ;save normalized result
  700.         MOV     CX,BX           ;for later use
  701.         LES     BX,DWORD PTR END_OFFSET     ;get end seg:off
  702.         CALL    NORMALIZE       ;change es:bx so 10h <= bx >=0
  703.         MOV     DX,ES           ;get end segment
  704.         SUB     DX,AX           ;calculate segments to search
  705.         MOV     SEARCH_SEGMENTS,DX
  706.         MOV     SEARCH_BYTES,BX ;# bytes in final segment
  707.         MOV     ES,AX           ;set es:bx to
  708.         MOV     BX,CX           ;start address
  709.         RET
  710. END_MINUS_START ENDP
  711. ;-----------------------------------------------------------------
  712. ;make 20 bit pointer in es:bx from segment:offset in es:bx
  713. ;-----------------------------------------------------------------
  714. NORMALIZE   PROC    NEAR
  715.             PUSH    AX          ;save these registers
  716.             PUSH    CX          ;for main routine
  717.             PUSH    DX
  718.             MOV     AX,BX       ;get the offset
  719.             MOV     CL,4        ;make into
  720.             SHR     AX,CL       ;number of paragraphs
  721.             MOV     DX,ES       ;get segment
  722.             ADD     DX,AX       ;add in number of paragraphs
  723.             MOV     ES,DX       ;back into segment
  724.             SHL     AX,CL       ;calc offset into segment
  725.             SUB     BX,AX       ;paras - paras mod 16
  726.             POP     DX          ;retstore registers
  727.             POP     CX          ;for main routine
  728.             POP     AX
  729.             RET
  730. NORMALIZE   ENDP
  731. ;-----------------------------------------------------------------
  732. ;si = string  cx = string_size
  733. ;search for match of string beginning at start_segment
  734. ;-----------------------------------------------------------------
  735. SEARCH_MEM      PROC    NEAR
  736.         MOV     DI,CX                   ;save string size
  737.         CALL    END_MINUS_START         ;calculate search length
  738. LOOK_AGAIN:
  739.         CMP     SEARCH_SEGMENTS,1000H   ;more than or equal 64k?
  740.         JAE     MORE_THAN_ENOUGH        ;if so, search 64k
  741.         MOV     AX,SEARCH_SEGMENTS      ;otherwise, get what's left
  742.         MOV     CL,4
  743.         SHL     AX,CL                   ;segs*16 = bytes to search
  744.         ADD     AX,SEARCH_BYTES         ;add in the last few bytes
  745.         JMP     SHORT LOOK              ;and go look
  746. MORE_THAN_ENOUGH:
  747.         MOV     AX,-1                   ;64k search
  748. LOOK:   SUB     AX,BX                   ;subtract initial offset
  749.         JC      SEARCH_NOT_FOUND        ;offset < search size?
  750.         SUB     AX,DI                   ;subtract off string size
  751.         JBE     SEARCH_NOT_FOUND        ;less than search size?
  752.         CMP     AX,DI                   ;amount left to search
  753.         JB      SEARCH_NOT_FOUND        ;less than search size?
  754.         MOV     DX,AX                   ;dx gets search size
  755.         MOV     CL,4
  756.         SHR     DX,CL                   ;number of segments to search
  757.         SUB     SEARCH_SEGMENTS,DX      ;decrease the amount to search
  758.                                         ;si = string  di = string size
  759.         CALL    SEARCH                  ;es:bx=ptr,ax=bytes to search
  760.         JZ      SEARCH_FOUND            ;if zero flag, string is found
  761.         ADD     AX,1                    ;next character after fail
  762.         MOV     BX,AX                   ;into es:bx
  763.         JNC     NOWR                    ;if offset rolls over
  764.         MOV     AX,ES                   ;add 64k
  765.         ADD     AX,1000H                ;to the
  766.         MOV     ES,AX                   ;offset
  767. NOWR:   CALL    NORMALIZE               ;set to start at the top of
  768.         JMP     LOOK_AGAIN              ;a new segment
  769. SEARCH_NOT_FOUND:
  770.         XOR     AX,AX                   ;start over
  771.         MOV     ES,AX
  772.         CMP     AL,1                    ;clear zero flag
  773. SEARCH_FOUND:
  774.         MOV     START_SEGMENT,ES        ;set page
  775.         MOV     START_OFFSET,AX         ;address of found string
  776.         RET
  777. SEARCH_MEM      ENDP
  778. ;-----------------------------------------------------------------
  779. ;si = string di = string size es:bx = pointer to buffer to search
  780. ;ax = number of bytes in buffer to search. Zero flag set if found
  781. ;-----------------------------------------------------------------
  782. SEARCH  PROC    NEAR            ;si points at string
  783.         PUSH    BX
  784.         PUSH    DI
  785.         PUSH    SI
  786.         XCHG    BX,DI           ;string size, ptr to data area
  787.         MOV     CX,AX           ;# chars in segment to search
  788. BYTE_ADD:
  789.         LODSB                   ;char for first part of search
  790. NEXT_SRCH:
  791.         REPNZ   SCASB           ;is first char in string in buffer
  792.         JNZ     NOT_FOUND       ;if not, no match
  793.         PUSH    DI              ;save against cmpsb
  794.         PUSH    SI
  795.         PUSH    CX
  796.         LEA     CX,[BX-1]       ;# chars in string - 1
  797.         JCXZ    ONE_CHAR        ;if one char search, we have found it
  798.         REP     CMPSB           ;otherwise compare rest of string
  799. ONE_CHAR:
  800.         POP     CX              ;restore for next cmpsb
  801.         POP     SI
  802.         POP     DI
  803.         JNZ     NEXT_SRCH       ;if zr = 0 then string not found
  804. NOT_FOUND:
  805.         LEA    AX,[DI-1]        ;ptr to last first character found
  806.         POP    SI
  807.         POP    DI
  808.         POP    BX
  809.         RET
  810. SEARCH  ENDP
  811. ;------------------------------------------------------------------
  812. ;dx=row:col,cx=max len,bx=replace character,si=prompt,di=sieve
  813. ;------------------------------------------------------------------
  814. INPUT   PROC    NEAR
  815.         PUSH    BP              ;create stack frame
  816.         MOV     BP,SP
  817.         SUB     SP,6
  818.         CALL    CURSOR_ON
  819.         MOV     [BP-2],CX       ;save size of destination
  820.         MOV     [BP-4],SI
  821.         MOV     [BP-6],DX
  822.         XOR     CX,CX           ;clear count of chars entered
  823. NEXT_DISPLAY:
  824.         PUSH    BX              ;save replace char
  825.         PUSH    SI
  826.         MOV     AL,[BP-5]       ;row
  827.         CBW                     ;into ax
  828.         MOV     BL,[BP-6]       ;col
  829.         XOR     BH,BH           ;into bx
  830.         MOV     SI,[BP-4]
  831.         CALL    DISPLAY_STRING  ;show string at si
  832.         POP     SI
  833.         POP     BX              ;restore replace char
  834.         PUSH    DS              ;set up string addressing
  835.         POP     ES
  836. NEXT_KEY:
  837.         CMP     BYTE PTR[SI],":";skip colon in destination
  838.         JNZ     NOT_COLON
  839.         INC     CX              ;next count
  840.         INC     DL              ;next col
  841.         INC     SI              ;point to next char
  842. NOT_COLON:
  843.         CALL    SETPOS          ;set cursor position
  844.         CALL    GETKEY          ;get next key
  845.         CMP     AH,1            ;if scan = 1
  846.         JZ      END_OF_INPUT    ;then it's esc
  847.         CMP     AH,1CH          ;if scan = 1ch
  848.         JZ      END_OF_INPUT    ;then it's carriage return
  849.         CMP     AH,L_ARR        ;if it's left arrow
  850.         JZ      BACK_SPACE      ;or
  851.         CMP     AH,0EH          ;if it's backspace key
  852.         JNZ     NOT_BACK_SPACE  ;then back up
  853. BACK_SPACE:
  854.         JCXZ    NEXT_KEY        ;if count 0 can't back up
  855.         DEC     CX              ;decrement count
  856.         DEC     DL              ;decrement column
  857.         DEC     SI              ;decrement pointer to chars
  858.         CMP     BYTE PTR[SI],":";if pointer is to colon,
  859.         JZ      BACK_SPACE      ;then back up again
  860.         MOV     BYTE PTR[SI],BL ;put replace character in
  861.         JMP     NEXT_DISPLAY    ;show line again
  862. NOT_BACK_SPACE:
  863.         CMP     CX,[BP-2]       ;is count = max count
  864.         JZ      NEXT_KEY        ;if so, can't put in buffer
  865. NEXT_INPUT:
  866.         CALL    VERIFY          ;ax = char di = sieve
  867.         JNZ     NEXT_KEY        ;if illegal char get new key
  868.         MOV     [SI],AL         ;otherwize put in buffer
  869.         INC     CX              ;next count
  870.         INC     SI              ;pointer to next char
  871.         INC     DL              ;next column
  872.         JMP     NEXT_DISPLAY    ;show line again
  873. END_OF_INPUT:
  874.         CMP     BL,"0"          ;if replace char is "0"
  875.         JZ      NO_ZERO         ;dont put terminator in
  876.         MOV     BYTE PTR[SI],0  ;terminate string
  877. NO_ZERO:
  878.         CALL    CURSOR_OFF
  879.         ADD     SP,6            ;clean off stack
  880.         POP     BP
  881.         RET
  882. INPUT   ENDP
  883. ;------------------------------------------------------------------
  884. GETKEY  PROC    NEAR
  885.         XOR     AH,AH           ;getkey function number
  886.         INT     16H             ;go get a key
  887.         RET                     ;return it
  888. GETKEY ENDP
  889. ;------------------------------------------------------------------
  890. ;ax = row  bx = col        displays string at ds:si
  891. ;------------------------------------------------------------------
  892. DISPLAY_STRING  PROC    NEAR
  893.                 PUSH    SI              ;save si for main routines
  894.                 PUSH    DI
  895.                 CALL    CALC_SCRN_ADDR  ;get es:di for row col
  896.                 MOV     AH,7            ;get normal attribute
  897. NEXT_CHAR:      LODSB                   ;get char from string
  898.                 OR      AL,AL           ;if zero
  899.                 JZ      LAST_CHAR       ;string has been printed
  900.                 STOSW                   ;char and attribute on screen
  901.                 JMP     NEXT_CHAR       ;until string has been printed
  902. LAST_CHAR:      POP     DI
  903.                 POP     SI              ;restore si for main routines
  904.                 RET
  905. DISPLAY_STRING  ENDP
  906. ;------------------------------------------------------------------
  907. ;ax = row bx= col, returns es:di pointing to the screen address
  908. ;------------------------------------------------------------------
  909. CALC_SCRN_ADDR  PROC    NEAR
  910.         PUSH    CX
  911.         PUSH    DX                      ;mul destroys dx
  912.         PUSH    AX                      ;save ax for later
  913.         MOV     ES,CS:BIOS_SEG          ;into es
  914.         MOV     AX,0B800H               ;CGA screen = b800h
  915.         CMP     ES:BYTE PTR[49H],7
  916.         JNZ     COLOR                   ;if 40:49 == 7 then
  917.         MOV     AH,0B0H                 ;screen seg = b000h
  918. COLOR:  MOV     ES,AX                   ;into es
  919.         POP     CX                      ;get row
  920.         MOV     AX,160                  ;160 bytes to a row of text
  921.         ADD     AX,CS:DIFF              ;# characters > 80
  922.         ADD     AX,CS:DIFF              ;# of attribute bytes > 80
  923.         MUL     CX                      ;row * 160 + diff*2
  924.         ADD     AX,BX                   ;+col
  925.         ADD     AX,BX                   ;row*160 + col*2
  926.         MOV     DI,AX                   ;es:di points to address
  927.         POP     DX                      ;restore dx
  928.         POP     CX
  929.         RET
  930. CALC_SCRN_ADDR  ENDP
  931. ;------------------------------------------------------------------
  932. ;ax = char di = sieve
  933. ;------------------------------------------------------------------
  934. VERIFY  PROC    NEAR
  935.         PUSH    CX              ;save registers for main routines
  936.         PUSH    DI
  937.         PUSH    SI
  938.         PUSH    DS
  939.         POP     ES
  940.         MOV     SI,DI           ;si = sieve address
  941.         CALL    STRLEN          ;how many chars in sieve (cx)
  942.         JCXZ    ANY_KEY         ;get key if no chars in sieve
  943.         CMP     AL,"A"
  944.         JB      NOT_SMALL
  945.         AND     AL,0DFH         ;make upper case to
  946. NOT_SMALL:                      ;search for char in the sieve
  947.         REPNZ   SCASB           ;set zero flag to indicate it
  948. ANY_KEY:
  949.         POP     SI              ;restore registers
  950.         POP     DI
  951.         POP     CX
  952.         RET
  953. VERIFY  ENDP
  954. ;----------------------------------------------------------------------
  955. STRLEN  PROC    NEAR
  956.         PUSH    SI              ;save si for main routines
  957.         PUSH    AX
  958.         MOV     CX,-1           ;count for string length
  959. NEXTS:  INC     CX              ;next count
  960.         LODSB                   ;next char
  961.         OR      AL,AL           ;is it a zero
  962.         JNZ     NEXTS           ;if not get next char
  963.         POP     AX
  964.         POP     SI              ;restore si for main routines
  965.         RET
  966. STRLEN  ENDP
  967. ;------------------------------------------------------------------
  968. ;input: al = ascii lsb ah = ascii msb
  969. ;   example: if hex is '3F', ah = '3' al = 'F'  result: al = 3Fh
  970. ;output: al = hex byte
  971. ;------------------------------------------------------------------
  972. ASCII_HEX_TO_HEX    PROC    NEAR
  973.             TEST    AH,40H          ;if "A" - "F"
  974.             JZ      AH_EXIT
  975.             SUB     AH,"A"-10       ;make 10-15
  976. AH_EXIT:    TEST    AL,40H          ;if "A" - "F"
  977.             JZ      AL_EXIT
  978.             SUB     AL,"A"-10       ;make 10-15
  979. AL_EXIT:    AND     AX,0F0FH        ;if "0" - "9"
  980.             SHL     AL,1
  981.             SHL     AL,1
  982.             SHL     AL,1
  983.             SHL     AL,1            ;make 0-9
  984.             OR      AL,AH           ;combine msn and lsn
  985.             RET
  986. ASCII_HEX_TO_HEX    ENDP
  987. ;------------------------------------------------------------------
  988. ;input: al = char to be translated:
  989. ;    example: if hex is '3F', al = '3' ah = 'F'
  990. ;output: al = msb of translation, ah = lsb of translation
  991. ;------------------------------------------------------------------
  992. HEX_TO_ASCII_HEX   PROC    NEAR     ;CREATE MACHINE CODE to:
  993.             DB      0D4H,10H        ;div AL/16-remainder in al
  994.             OR      AX,3030H        ;make ascii
  995.             CMP     AL,"9"
  996.             JBE     ALEXIT
  997.             ADD     AL,7            ;if a - f make "A" - "F"
  998. ALEXIT:     CMP     AH,"9"
  999.             JBE     AHEXIT
  1000.             ADD     AH,7            ;if a - f make "A" - "F"
  1001. AHEXIT:     XCHG    AL,AH
  1002.             RET
  1003. HEX_TO_ASCII_HEX    ENDP
  1004. ;-----------------------------------------------------------------
  1005. EVEN    ; VIDEO & STACK included to insure that TSR will NOT grow!
  1006.             DB 4000 DUP ('V')   ;start of memory used to save screen
  1007.             DB    4 DUP ('B')   ;BackGround Processing Minimum
  1008.             DB  256 DUP ('S')   ;PopUp Main Processing Stack
  1009. TopStack    LABEL BYTE          ;marks end of resident code
  1010.             DB  " Heart&Mind "  ;identify reviser
  1011. ;-----------------------------------------------------------------
  1012. INSTALLED_SEGMENT   DW  0
  1013. DISABLED    DB  CR,LF,"RAMVIEW IS DISABLED",CR,LF,"$"
  1014. ENABLED     DB  CR,LF,"RAMVIEW IS RE-ENABLED",CR,LF,"$"
  1015. ;-----------------------------------------------------------------
  1016. ;determine if vectors have changed since program was installed
  1017. ;-----------------------------------------------------------------
  1018. HOOKED_VECTORS_SAME?    PROC    NEAR
  1019.         MOV     CX,INSTALLED_SEGMENT    ;get executing segment
  1020.         XOR     AX,AX                   ;interrupt table segment
  1021.         MOV     ES,AX                   ;into the extra segment
  1022.         CMP     CX,ES:[10h*4+2]         ;If INT 10h Vector
  1023.         JNZ     VECTOR_CHANGED          ;Or INT 09h Vector
  1024.         CMP     CX,ES:[9*4+2]           ;Is NOT HERE
  1025. VECTOR_CHANGED:                         ;Then NZ Flag
  1026.         RET
  1027. HOOKED_VECTORS_SAME?    ENDP
  1028. ;-----------------------------------------------------------------
  1029. ;determine if program is already installed
  1030. ;-----------------------------------------------------------------
  1031. PROGRAM_ALREADY_IN      PROC    NEAR
  1032.         NOT     WORD PTR BEGIN          ;only search for active copy
  1033.         MOV     START_SEGMENT,60h       ;start after DOS area
  1034.         MOV     START_OFFSET,0
  1035.         MOV     END_SEGMENT,CS          ;stop looking before reaching
  1036.         MOV     END_OFFSET,0            ;this copy in memory
  1037.         MOV     SI,OFFSET BEGIN         ;compare from modified bytes
  1038.         MOV     CX,25                   ;for enough of a text match
  1039.         CALL    SEARCH_MEM              ;use program's built-in proc
  1040.         PUSHF                           ;Preserve Search Result
  1041.         MOV     AX,START_SEGMENT        ;get address of find and
  1042.         MOV     INSTALLED_SEGMENT,AX    ;save as installed address
  1043.         MOV     AX,START_OFFSET
  1044.         MOV     CL,4                    ;make into
  1045.         SHR     AX,CL                   ;paragraphs
  1046.         SUB     AX,10h                  ;less PSP
  1047.         ADD     INSTALLED_SEGMENT,AX
  1048.         MOV     START_SEGMENT,0         ;reset starting address
  1049.         MOV     START_OFFSET,0
  1050.         MOV     END_OFFSET,0Fh          ;reset ending address
  1051.         MOV     END_SEGMENT,0FFFFh
  1052.         POPF                            ;Restore Search Result
  1053.         RET
  1054. PROGRAM_ALREADY_IN      ENDP
  1055. ;-----------------------------------------------------------------
  1056. ;UnInstall routines
  1057. ;-----------------------------------------------------------------
  1058. UNINSTALL   PROC    NEAR
  1059.             CALL    HOOKED_VECTORS_SAME?;If all vectors still hooked
  1060.             JZ      UNINSTALL_OK        ;Then Ok to Un-Install
  1061.             NOT     WORD PTR BEGIN      ;Else change disabled flag
  1062.             MOV     ES,INSTALLED_SEGMENT; in the installed program
  1063.             NOT     ES:DISABLE
  1064.             MOV     DX,OFFSET ENABLED
  1065.             CMP     ES:DISABLE,-1       ;If NOT OFF
  1066.             JNE     SAY_STATUS          ;Then ENABLED
  1067.             MOV     DX,OFFSET DISABLED  ;Else DISABLED
  1068. SAY_STATUS: MOV     AH,9
  1069.             INT     21h
  1070.             RET                         ;PROCEDURE EXIT
  1071. UNINSTALL_OK:
  1072.             MOV     ES,INSTALLED_SEGMENT;Get Resident's PSP
  1073.             MOV     DX,ES:WORD PTR ADDR_INT9H
  1074.             MOV     DS,ES:WORD PTR ADDR_INT9H+2
  1075.             MOV     AX,2509h            ;Restore INT 9H Vector
  1076.             INT     21h
  1077.             MOV     DX,ES:WORD PTR ADDR_INT10H
  1078.             MOV     DS,ES:WORD PTR ADDR_INT10H+2
  1079.             MOV     AX,2510h            ;Restore INT10H Vector
  1080.             INT     21h
  1081.             PUSH    ES
  1082.             MOV     ES,ES:[2Ch]         ;Environment Segment in ES
  1083.             MOV     AH,49h              ;Free Environment Segment
  1084.             INT     21h
  1085.             POP     ES
  1086.             MOV     AH,49h              ;Free Program's Memory Block
  1087.             INT     21h
  1088.             PUSH    CS                  ;Restore Code to
  1089.             POP     DS                  ;Data Segment Register
  1090.             MOV     DX,OFFSET UNINSTALLED
  1091.             JMP     SAY_STATUS
  1092. UNINSTALL   ENDP
  1093. ;-----------------------------------------------------------------
  1094. INSTALL     PROC    NEAR
  1095.             MOV     CL,9                ;link vector for INT 9H
  1096.             MOV     SI,OFFSET ADDR_INT9H
  1097.             MOV     DI,OFFSET INT9H
  1098.             CALL    INSTALL_VECTOR
  1099.             MOV     CL,10h              ;link vector for INT10H
  1100.             MOV     SI,OFFSET ADDR_INT10H
  1101.             MOV     DI,OFFSET INT10H
  1102.             CALL    INSTALL_VECTOR
  1103.             RET
  1104. INSTALL     ENDP
  1105. ;-----------------------------------------------------------------
  1106. INSTALL_VECTOR      PROC    NEAR
  1107.             MOV     AL,CL               ;get vector number
  1108.             MOV     AH,35h              ;get interrupt number
  1109.             INT     21h
  1110.             MOV     [SI],BX             ;save interrupt vector
  1111.             MOV     [SI+2],ES
  1112.             MOV     DX,DI               ;get replacement address
  1113.             MOV     AH,25h              ;set vector address
  1114.             MOV     AL,CL               ;for INT number
  1115.             INT     21h
  1116.             RET
  1117. INSTALL_VECTOR      ENDP
  1118. ;-----------------------------------------------------------------
  1119. _TEXT   ENDS
  1120.         END     BEGIN
  1121.